package com.chengzhi.state;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.persist.StateMachinePersister;
import org.springframework.stereotype.Service;

import java.util.concurrent.ConcurrentHashMap;

/**
 * @author ruanchengzhi
 * @description: TODO
 * @date 2019/7/23 16:53
 */
@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private StateMachine<OrderStatus, OrderEvent> stateMachine;

    @Autowired
    private StateMachinePersister<OrderStatus, OrderEvent, Order> persister;

    private volatile int id = 1;
    private ConcurrentHashMap<Integer, Order> orderMap = new ConcurrentHashMap<>();

    @Override
    public Order creat() {
        Order order = new Order();
        order.setId(id++);
        order.setStatus(OrderStatus.WAIT_PAYMENT);
        orderMap.put(order.getId(), order);
        return order;
    }

    @Override
    public Order pay(int id) {
        Order order = orderMap.get(id);
        Message<OrderEvent> message = MessageBuilder.withPayload(OrderEvent.PAYED).setHeader("order", order).build();
        if (!sendEvent(message, order)) {
            System.out.println("-----PAYED-------Failed");
        }
        return order;
    }

    @Override
    public Order deliver(int id) {
        Order order = orderMap.get(id);
        Message<OrderEvent> message = MessageBuilder.withPayload(OrderEvent.DELIVERY).setHeader("order", order).build();
        if (!sendEvent(message, order)) {
            System.out.println("------DELIVERY------Failed");
        }
        return order;
    }

    @Override
    public Order receive(int id) {
        Order order = orderMap.get(id);
        Message<OrderEvent> message = MessageBuilder.withPayload(OrderEvent.RECEIVED).setHeader("order", order).build();
        if (!sendEvent(message, order)) {
            System.out.println("------RECEIVED------Failed");
        }
        return order;
    }

    @Override
    public ConcurrentHashMap<Integer, Order> getOrders() {
        return orderMap;
    }

    private synchronized boolean sendEvent(Message<OrderEvent> message, Order order) {
        boolean result = false;
        try {
            stateMachine.start();
            persister.restore(stateMachine, order);
            Thread.sleep(1000);
            result = stateMachine.sendEvent(message);
            persister.persist(stateMachine, order);
        } catch (Throwable e) {
            e.printStackTrace();
        } finally {
            stateMachine.stop();
        }
        return result;
    }
}
